/* 常用工具包方法 */
const { spawnSync } = require('child_process');
const CONSTS = require('@lib/consts/index');

/**
 * 校验url合法
 * @param {*} url 待校验url
 * @returns 是否合法-布尔值
 */
const isValidURL = (url) => {
  try {
    const urlObj = new URL(url);
    return urlObj;
  } catch (error) {
    return false;
  }
};

/**
 * 校验字符串合法（非空、非undefined、非null）
 * @param {*} str 待校验字符串
 * @returns 是否合法-布尔值
 */
const isValidStr = (str) => {
  return typeof str === 'string' && str.trim() !== '';
};

/**
 * 校验输入是否正数
 * @param {*} inputVal 输入
 * @returns 是否正数-布尔值
 */
const isPositiveNum = (inputVal) => {
  const val = +inputVal;
  if (!isNaN(val) && val > 0) {
    return true;
  }
  return false;
};

/**
 * 根据git地址提取目录名称
 * @param {*} gitUrl git地址
 * @returns 目录名称
 */
const extractDirNameByGitUrl = (gitUrl) => {
  // 提取仓库地址中的路径部分
  const path = gitUrl.match(/\/(.+)\.git$/)[1];
  // 获取最后一个斜杠后的目录名称
  const directoryName = path.split('/').pop();
  return directoryName;
};

/**
 * 判断是否前端项目
 * @param {*} fileNameList 文件名称列表，比如：['index.html']
 * @returns 是否前端项目-布尔值
 */
const isFePrj = (fileNameList) => {
  // 判断是否包含前端项目常用的文件
  const feFilesSuffixList = CONSTS.FE_FILES_SUFFIX;
  return fileNameList.some(fileName => {
    const fileExtension = fileName.substr(fileName.lastIndexOf('.'));
    return feFilesSuffixList.includes(fileExtension);
  });
};

/**
 * 字节(B) -> KB
 * @param {*} bytes 字节数
 * @returns KB数
 */
const bytes2KB = (bytes) => {
  const kilobytes = +bytes / 1024;
  return +kilobytes.toFixed(2);
};

/**
 * 校验数组是否有值
 * @param {*} arr 待校验的数组
 * @returns 数组是否有值-布尔值
 */
const isValuableArray = (arr) => {
  return Array.isArray(arr) && arr.length;
};

/**
 * 将原始数据根据field整合成新的数组，比如：
 * const originalArray = [
 *   { title: "A", value: [1, 2, 3] },
 *   { title: "B", value: [1, 2] },
 *   { title: "A", value: [4, 5, 6] },
 *   { title: "B", value: [3] }
 * ];
 * const newArray = mergeArrayByField(originalArray, 'title', 'value');
 * newArray = [
 *   { title: "A", value: [1, 2, 3, 4, 5, 6] },
 *   { title: "B", value: [1, 2, 3] }
 * ];
 * @param {*} originalArray 原始数组
 * @param {*} field merge依据的字段
 * @param {*} listField 列表数据对应的字段
 * @returns 整合后的新数组
 */
const mergeArrayByField = (originalArray, field, listField) => {
  if (!isValuableArray(originalArray)) {
    return [];
  }
  const mergedObject = {};
  // 循环遍历原始数组
  originalArray.forEach(item => {
    const name = item[field];
    const data = item[listField] || [];
    if (mergedObject[name] && isValuableArray(mergedObject[name])) {
      mergedObject[name] = mergedObject[name].concat(data);
    } else {
      mergedObject[name] = data;
    }
  });
  const ret = [];
  Object.keys(mergedObject).forEach(key => {
    const item = {};
    item[field] = key;
    item[listField] = mergedObject[key];
    ret.push(item);
  });
  return ret;
};

/**
 * 获取字符串内容的字节数
 * @param {*} content 字符串内容
 * @returns 字符串的字节数
 */
const getContentSize = (content) => {
  return Buffer.from(content, 'utf-8').length;
};

/**
 * html字符串替换方法-实现将 < 和 > 转化为 &lt; 和 &gt;
 * @param {} input html字符串
 * @returns 替换后的字符串
 */
const escapeHTML = (input) => {
  // 替换 < 和 >
  return input.replace(/[<>]/g, function(match) {
    // 使用对象映射进行替换
    const replacements = { '<': '&lt;', '>': '&gt;' };
    return replacements[match];
  });
};

/**
 * 子进程执行npm config set registry命令设置npm代理源
 * @param {*} registry npm代理源
 * @returns 是否执行成功-布尔值
 */
const npmSetRegistrySync = (registry) => {
  try {
    console.log(`执行 npm config set registry ${registry}`);
    const result = spawnSync('npm', ['config', 'set', 'registry', 'registry']);
    // 检查执行结果
    if (+result.status !== 0) {
      console.error(`执行 npm config set registry ${registry} 失败`);
      return false;
    }
    console.log(`执行 npm config set registry ${registry} 成功`);
    return true;
  } catch (error) {
    console.error(`执行 npm config set registry ${registry} 出错: ${error}`);
    return false;
  }
};

/**
 * 子进程执行npm install 安装npm依赖
 * @returns 是否执行成功-布尔值
 */
const npmInstallSync = () => {
  try {
    console.log('执行 npm install');
    const result = spawnSync('npm', ['install'], {
      stdio: 'inherit', // 将子进程的输入输出流连接到父进程的输入输出流
      shell: true // 在 shell 中执行命令
    });
    // 检查执行结果
    if (+result.status !== 0) {
      console.error('执行 npm install 失败');
      return false;
    }
    console.log('执行 npm install 成功');
    return true;
  } catch (error) {
    console.error(`执行 npm install 出错: ${error}`);
    return false;
  }
};

module.exports = {
  isValidURL,
  isValidStr,
  isPositiveNum,
  extractDirNameByGitUrl,
  isFePrj,
  bytes2KB,
  isValuableArray,
  mergeArrayByField,
  getContentSize,
  escapeHTML,
  npmSetRegistrySync,
  npmInstallSync
};
